library(tidyverse)
library(corrplot)
library(factoextra)
library(cluster)
library(gt)
library(paletteer)
library(scales)
library(ggtext)
library(glue)
library(ggpubr)
library(janitor)
theme_set(theme_minimal())
plot_theme <- theme(
    plot.title=element_markdown( 
                                 face='bold' ,
                                 size = 20 , ),
    plot.subtitle=element_markdown(
                                 face='bold' ,
                                 size = 14 , ),
    axis.text.x=element_text( size=14),
    axis.text.y=element_text( size=14),
    panel.grid.major = element_blank(),
    panel.grid.minor = element_blank(),
    legend.position = "none",
    panel.background = element_rect(fill = "#E6F8B2") ,
    plot.background = element_rect(fill = "#E6F8B2")
  )
dog_breed <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2022/2022-02-01/breed_traits.csv' )
trait_description <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2022/2022-02-01/trait_description.csv')
breed_rank_all <- readr::read_csv('https://raw.githubusercontent.com/rfordatascience/tidytuesday/master/data/2022/2022-02-01/breed_rank.csv')
str(dog_breed)
# one record has 0 for all -- remove it here
dog_breed <-  dog_breed %>% clean_names() %>%  filter(affectionate_with_family > 0)
# create a df of only numeric data
dog_num <- dog_breed %>%
  select(-c( coat_length , coat_type ) , -1)

rownames(dog_num) <- dog_breed$breed
Setting row names on a tibble is deprecated.
dog_num %>%
  pivot_longer( cols = everything() , names_to = 'col' , values_to = 'rank') %>%
  ggplot(aes(y=col,x=rank)) +
  geom_boxplot() +
  geom_jitter()

dog_num %>% scale() %>% as.data.frame() %>%
  pivot_longer( cols = everything() , names_to = 'col' , values_to = 'rank') %>%
  ggplot(aes(y=col,x=rank)) +
  geom_boxplot() +
  geom_jitter()

corrplot(cor(dog_num),        # Correlation matrix
         method = "number", # Correlation plot method
         type = "full",    # Correlation plot style (also "upper" and "lower")
         diag = TRUE,      # If TRUE (default), adds the diagonal
         tl.col = "black", # Labels color
         bg = "white",     # Background color
         title = "",       # Main title
         col = NULL)       # Color palette

corrplot.mixed(cor(dog_num),
               lower = "circle",
               upper = "number",
               tl.col = "black")

Start the clustering

# chose optimal number of clusters
fviz_nbclust(dog_num, kmeans, method = "wss")

# number of clusters
num_clusters = 8

#make this example reproducible
set.seed(1)

#perform k-means clustering with k = 4 clusters
km <- kmeans(dog_num, centers = num_clusters, nstart = 25)

#plot results of final k-means model
fviz_cluster(km, data = dog_num)


# add clusters to data
dog_breed <- cbind(dog_breed, cluster = km$cluster)
dog_breed %>%
  select(breed,cluster) %>%
  count(cluster)
dog_breed %>%
  select(-c(coat_length, coat_type ) , -1) %>%
  group_by(cluster) %>%
  summarise(across(everything(), mean)) %>%
  t() %>%
  as.data.frame() %>%
  mutate(rowname = rownames(.)) %>%
  rename_with(~gsub('V','',.x)) %>%
  filter( !rowname == 'cluster') %>%
  gt() %>%
  data_color(
    columns = everything(),
    colors = scales::col_numeric(
      palette = paletteer::paletteer_d(
        palette = "ggsci::red_material"
        ) %>% as.character(),
      domain = NULL
      ))
dog_breed %>%
  select(-c(coat_length, coat_type ) , -1) %>%
  pivot_longer( cols = c(-cluster) , names_to = 'col' , values_to = 'rank') %>%
  ggplot(aes(y=col,x=rank,color=as.factor(cluster))) +
  #geom_boxplot() +
  geom_jitter()

dog_breed %>%
  select(-c(coat_length, coat_type ) , -1) %>%
  group_by(cluster) %>%
  summarise(across(everything(), mean)) %>%
  pivot_longer( cols = c(-cluster) , names_to = 'col' , values_to = 'rank') %>%
  ggplot(aes(y=col,x=rank,color=as.factor(cluster) , label=cluster)) +
  geom_text(position=position_jitter(width=0.5,height=0.0) , size=10) +
  plot_theme
`summarise()` ungrouping output (override with `.groups` argument)

dog_scaled_vars <- dog_breed %>%
  select(-c(breed , coat_length, coat_type , cluster )) %>%
  scale() %>%
  as.data.frame() %>%
  mutate(cluster = dog_breed$cluster)
 
plot_clust <- dog_scaled_vars %>%
  #select(-c(coat_length, coat_type ) , -1) %>%
  group_by(cluster) %>%
  summarise(across(everything(), mean) , .groups = 'drop') %>%
  pivot_longer( cols = c(-cluster) , names_to = 'col' , values_to = 'rank') %>%
  ggplot(aes(x=col,y=rank,color=as.factor(cluster) , label=cluster , group=cluster)) +
  geom_point(size=10) +
  geom_line(size=1.5)  +
  geom_text(color='white') +
  annotate(
    geom = "text", x = 'adaptability_level', y = -1.5, 
    label = 'Rated Lower', hjust = 0, vjust = 2, size = 8) +
  annotate(
    geom = "text", x = 'adaptability_level', y = 0.75, 
    label = 'Rated Higher', hjust = 0, vjust = 2, size = 8) +
  plot_theme +
  theme(axis.title.x=element_blank(),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank()) +
  #ylim(-1,3) +
  coord_flip() +
  labs(title='Mean of Attributes for Each Cluster of Dog Breeds' ,
       subtitle = '' ,
      x='',y='' , 
      caption='Plot: @itsnatrivera    Data: American Kennel Club') +
  scale_color_manual(breaks = c('1','2','3','4','5','6','7','8'),
                     values=c("#009E73", "#E69F00", "#56B4E9", "#000000",
                              "#293352", "#0072B2", "#D55E00", "#CC79A7")) 

plot_clust

plot_names <- dog_breed %>%
  group_by(cluster) %>%
  mutate(count = sequence(n())  ,
         countx = ifelse(count%%2==0,-0.5,0.5) ) %>%
  ggplot(aes(x=countx,y=count , label=breed ,color=as.factor(cluster)  )) +
 geom_text(size=4.8) +
  facet_wrap(~cluster , ncol = 2 ,  scales="free_y") +
  xlim(c(-1,1)) +
  plot_theme +
  theme(axis.title.x=element_blank(),
        axis.text.x=element_blank(),
        axis.ticks.x=element_blank(),
        axis.title.y=element_blank(),
        axis.text.y=element_blank(),
        axis.ticks.y=element_blank() ,
        strip.text.x = element_text(
              size = 12, color = "white", face = "bold"),
        strip.background = element_rect(
            color="black", fill="#000000", size=1.5, linetype="solid"),
        panel.border = element_rect(color = "black",
                                    fill = NA,
                                    size = 2)) +
  labs(title='8 Clusters of Dog Breeds' ,
       subtitle = '' ) +
  scale_color_manual(breaks = c('1','2','3','4','5','6','7','8'),
                     values=c("#009E73", "#E69F00", "#56B4E9", "#000000",
                              "#293352", "#0072B2", "#D55E00", "#CC79A7"))
      

plot_names

ggarrange(plot_names , plot_clust)

LS0tCnRpdGxlOiAiUiBOb3RlYm9vayIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShjb3JycGxvdCkKbGlicmFyeShmYWN0b2V4dHJhKQpsaWJyYXJ5KGNsdXN0ZXIpCmxpYnJhcnkoZ3QpCmxpYnJhcnkocGFsZXR0ZWVyKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShnZ3RleHQpCmxpYnJhcnkoZ2x1ZSkKbGlicmFyeShnZ3B1YnIpCmxpYnJhcnkoamFuaXRvcikKdGhlbWVfc2V0KHRoZW1lX21pbmltYWwoKSkKYGBgCgoKYGBge3J9CnBsb3RfdGhlbWUgPC0gdGhlbWUoCiAgICBwbG90LnRpdGxlPWVsZW1lbnRfbWFya2Rvd24oIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWNlPSdib2xkJyAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAyMCAsICksCiAgICBwbG90LnN1YnRpdGxlPWVsZW1lbnRfbWFya2Rvd24oCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhY2U9J2JvbGQnICwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IDE0ICwgKSwKICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dCggc2l6ZT0xNCksCiAgICBheGlzLnRleHQueT1lbGVtZW50X3RleHQoIHNpemU9MTQpLAogICAgcGFuZWwuZ3JpZC5tYWpvciA9IGVsZW1lbnRfYmxhbmsoKSwKICAgIHBhbmVsLmdyaWQubWlub3IgPSBlbGVtZW50X2JsYW5rKCksCiAgICBsZWdlbmQucG9zaXRpb24gPSAibm9uZSIsCiAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGZpbGwgPSAiI0U2RjhCMiIpICwKICAgIHBsb3QuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChmaWxsID0gIiNFNkY4QjIiKQogICkKYGBgCgogCiAKCmBgYHtyfQpkb2dfYnJlZWQgPC0gcmVhZHI6OnJlYWRfY3N2KCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L21hc3Rlci9kYXRhLzIwMjIvMjAyMi0wMi0wMS9icmVlZF90cmFpdHMuY3N2JyApCnRyYWl0X2Rlc2NyaXB0aW9uIDwtIHJlYWRyOjpyZWFkX2NzdignaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL3Jmb3JkYXRhc2NpZW5jZS90aWR5dHVlc2RheS9tYXN0ZXIvZGF0YS8yMDIyLzIwMjItMDItMDEvdHJhaXRfZGVzY3JpcHRpb24uY3N2JykKYnJlZWRfcmFua19hbGwgPC0gcmVhZHI6OnJlYWRfY3N2KCdodHRwczovL3Jhdy5naXRodWJ1c2VyY29udGVudC5jb20vcmZvcmRhdGFzY2llbmNlL3RpZHl0dWVzZGF5L21hc3Rlci9kYXRhLzIwMjIvMjAyMi0wMi0wMS9icmVlZF9yYW5rLmNzdicpCmBgYAoKIAoKIAoKIAoKYGBge3J9CnN0cihkb2dfYnJlZWQpCmBgYAoKIAoKYGBge3J9CiMgb25lIHJlY29yZCBoYXMgMCBmb3IgYWxsIC0tIHJlbW92ZSBpdCBoZXJlCmRvZ19icmVlZCA8LSAgZG9nX2JyZWVkICU+JSBjbGVhbl9uYW1lcygpICU+JSAgZmlsdGVyKGFmZmVjdGlvbmF0ZV93aXRoX2ZhbWlseSA+IDApCmBgYAoKIAoKIAoKIAoKYGBge3J9CiMgY3JlYXRlIGEgZGYgb2Ygb25seSBudW1lcmljIGRhdGEKZG9nX251bSA8LSBkb2dfYnJlZWQgJT4lCiAgc2VsZWN0KC1jKCBjb2F0X2xlbmd0aCAsIGNvYXRfdHlwZSApICwgLTEpCgojcm93bmFtZXMoZG9nX251bSkgPC0gZG9nX2JyZWVkJGJyZWVkCmBgYAoKIAoKIAoKYGBge3J9CmRvZ19udW0gJT4lCiAgcGl2b3RfbG9uZ2VyKCBjb2xzID0gZXZlcnl0aGluZygpICwgbmFtZXNfdG8gPSAnY29sJyAsIHZhbHVlc190byA9ICdyYW5rJykgJT4lCiAgZ2dwbG90KGFlcyh5PWNvbCx4PXJhbmspKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGdlb21faml0dGVyKCkKYGBgCgogCgogCgpgYGB7cn0KZG9nX251bSAlPiUgc2NhbGUoKSAlPiUgYXMuZGF0YS5mcmFtZSgpICU+JQogIHBpdm90X2xvbmdlciggY29scyA9IGV2ZXJ5dGhpbmcoKSAsIG5hbWVzX3RvID0gJ2NvbCcgLCB2YWx1ZXNfdG8gPSAncmFuaycpICU+JQogIGdncGxvdChhZXMoeT1jb2wseD1yYW5rKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcigpCmBgYAoKIAoKIAoKIAoKIAoKYGBge3J9CmNvcnJwbG90KGNvcihkb2dfbnVtKSwgICAgICAgICMgQ29ycmVsYXRpb24gbWF0cml4CiAgICAgICAgIG1ldGhvZCA9ICJudW1iZXIiLCAjIENvcnJlbGF0aW9uIHBsb3QgbWV0aG9kCiAgICAgICAgIHR5cGUgPSAiZnVsbCIsICAgICMgQ29ycmVsYXRpb24gcGxvdCBzdHlsZSAoYWxzbyAidXBwZXIiIGFuZCAibG93ZXIiKQogICAgICAgICBkaWFnID0gVFJVRSwgICAgICAjIElmIFRSVUUgKGRlZmF1bHQpLCBhZGRzIHRoZSBkaWFnb25hbAogICAgICAgICB0bC5jb2wgPSAiYmxhY2siLCAjIExhYmVscyBjb2xvcgogICAgICAgICBiZyA9ICJ3aGl0ZSIsICAgICAjIEJhY2tncm91bmQgY29sb3IKICAgICAgICAgdGl0bGUgPSAiIiwgICAgICAgIyBNYWluIHRpdGxlCiAgICAgICAgIGNvbCA9IE5VTEwpICAgICAgICMgQ29sb3IgcGFsZXR0ZQpgYGAKCiAKCiAKCmBgYHtyfQpjb3JycGxvdC5taXhlZChjb3IoZG9nX251bSksCiAgICAgICAgICAgICAgIGxvd2VyID0gImNpcmNsZSIsCiAgICAgICAgICAgICAgIHVwcGVyID0gIm51bWJlciIsCiAgICAgICAgICAgICAgIHRsLmNvbCA9ICJibGFjayIpCmBgYAoKIAojIyMgU3RhcnQgdGhlIGNsdXN0ZXJpbmcKIAoKYGBge3J9CiMgY2hvc2Ugb3B0aW1hbCBudW1iZXIgb2YgY2x1c3RlcnMKZnZpel9uYmNsdXN0KGRvZ19udW0sIGttZWFucywgbWV0aG9kID0gIndzcyIpCmBgYAoKIAoKIAoKIAoKIAoKYGBge3J9CiMgbnVtYmVyIG9mIGNsdXN0ZXJzCm51bV9jbHVzdGVycyA9IDgKCiNtYWtlIHRoaXMgZXhhbXBsZSByZXByb2R1Y2libGUKc2V0LnNlZWQoMSkKCiNwZXJmb3JtIGstbWVhbnMgY2x1c3RlcmluZyB3aXRoIGsgPSA0IGNsdXN0ZXJzCmttIDwtIGttZWFucyhkb2dfbnVtLCBjZW50ZXJzID0gbnVtX2NsdXN0ZXJzLCBuc3RhcnQgPSAyNSkKCiNwbG90IHJlc3VsdHMgb2YgZmluYWwgay1tZWFucyBtb2RlbApmdml6X2NsdXN0ZXIoa20sIGRhdGEgPSBkb2dfbnVtKQoKIyBhZGQgY2x1c3RlcnMgdG8gZGF0YQpkb2dfYnJlZWQgPC0gY2JpbmQoZG9nX2JyZWVkLCBjbHVzdGVyID0ga20kY2x1c3RlcikKYGBgCgogCgogCgogCgpgYGB7cn0KZG9nX2JyZWVkICU+JQogIHNlbGVjdChicmVlZCxjbHVzdGVyKSAlPiUKICBjb3VudChjbHVzdGVyKQpgYGAKCiAKCiAKCmBgYHtyfQpkb2dfYnJlZWQgJT4lCiAgc2VsZWN0KC1jKGNvYXRfbGVuZ3RoLCBjb2F0X3R5cGUgKSAsIC0xKSAlPiUKICBncm91cF9ieShjbHVzdGVyKSAlPiUKICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgbWVhbikpICU+JQogIHQoKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgbXV0YXRlKHJvd25hbWUgPSByb3duYW1lcyguKSkgJT4lCiAgcmVuYW1lX3dpdGgofmdzdWIoJ1YnLCcnLC54KSkgJT4lCiAgZmlsdGVyKCAhcm93bmFtZSA9PSAnY2x1c3RlcicpICU+JQogIGd0KCkgJT4lCiAgZGF0YV9jb2xvcigKICAgIGNvbHVtbnMgPSBldmVyeXRoaW5nKCksCiAgICBjb2xvcnMgPSBzY2FsZXM6OmNvbF9udW1lcmljKAogICAgICBwYWxldHRlID0gcGFsZXR0ZWVyOjpwYWxldHRlZXJfZCgKICAgICAgICBwYWxldHRlID0gImdnc2NpOjpyZWRfbWF0ZXJpYWwiCiAgICAgICAgKSAlPiUgYXMuY2hhcmFjdGVyKCksCiAgICAgIGRvbWFpbiA9IE5VTEwKICAgICAgKSkKYGBgCgogCgogCgpgYGB7cn0KZG9nX2JyZWVkICU+JQogIHNlbGVjdCgtYyhjb2F0X2xlbmd0aCwgY29hdF90eXBlICkgLCAtMSkgJT4lCiAgcGl2b3RfbG9uZ2VyKCBjb2xzID0gYygtY2x1c3RlcikgLCBuYW1lc190byA9ICdjb2wnICwgdmFsdWVzX3RvID0gJ3JhbmsnKSAlPiUKICBnZ3Bsb3QoYWVzKHk9Y29sLHg9cmFuayxjb2xvcj1hcy5mYWN0b3IoY2x1c3RlcikpKSArCiAgI2dlb21fYm94cGxvdCgpICsKICBnZW9tX2ppdHRlcigpCmBgYAoKIAoKIAoKIAoKIAoKIAoKYGBge3Igd2FybmluZz1GQUxTRX0KZG9nX2JyZWVkICU+JQogIHNlbGVjdCgtYyhjb2F0X2xlbmd0aCwgY29hdF90eXBlICkgLCAtMSkgJT4lCiAgZ3JvdXBfYnkoY2x1c3RlcikgJT4lCiAgc3VtbWFyaXNlKGFjcm9zcyhldmVyeXRoaW5nKCksIG1lYW4pKSAlPiUKICBwaXZvdF9sb25nZXIoIGNvbHMgPSBjKC1jbHVzdGVyKSAsIG5hbWVzX3RvID0gJ2NvbCcgLCB2YWx1ZXNfdG8gPSAncmFuaycpICU+JQogIGdncGxvdChhZXMoeT1jb2wseD1yYW5rLGNvbG9yPWFzLmZhY3RvcihjbHVzdGVyKSAsIGxhYmVsPWNsdXN0ZXIpKSArCiAgZ2VvbV90ZXh0KHBvc2l0aW9uPXBvc2l0aW9uX2ppdHRlcih3aWR0aD0wLjUsaGVpZ2h0PTAuMCkgLCBzaXplPTEwKSArCiAgcGxvdF90aGVtZQpgYGAKCiAKCiAKCmBgYHtyICB9CmRvZ19zY2FsZWRfdmFycyA8LSBkb2dfYnJlZWQgJT4lCiAgc2VsZWN0KC1jKGJyZWVkICwgY29hdF9sZW5ndGgsIGNvYXRfdHlwZSAsIGNsdXN0ZXIgKSkgJT4lCiAgc2NhbGUoKSAlPiUKICBhcy5kYXRhLmZyYW1lKCkgJT4lCiAgbXV0YXRlKGNsdXN0ZXIgPSBkb2dfYnJlZWQkY2x1c3RlcikKIApwbG90X2NsdXN0IDwtIGRvZ19zY2FsZWRfdmFycyAlPiUKICAjc2VsZWN0KC1jKGNvYXRfbGVuZ3RoLCBjb2F0X3R5cGUgKSAsIC0xKSAlPiUKICBncm91cF9ieShjbHVzdGVyKSAlPiUKICBzdW1tYXJpc2UoYWNyb3NzKGV2ZXJ5dGhpbmcoKSwgbWVhbikgLCAuZ3JvdXBzID0gJ2Ryb3AnKSAlPiUKICBwaXZvdF9sb25nZXIoIGNvbHMgPSBjKC1jbHVzdGVyKSAsIG5hbWVzX3RvID0gJ2NvbCcgLCB2YWx1ZXNfdG8gPSAncmFuaycpICU+JQogIGdncGxvdChhZXMoeD1jb2wseT1yYW5rLGNvbG9yPWFzLmZhY3RvcihjbHVzdGVyKSAsIGxhYmVsPWNsdXN0ZXIgLCBncm91cD1jbHVzdGVyKSkgKwogIGdlb21fcG9pbnQoc2l6ZT0xMCkgKwogIGdlb21fbGluZShzaXplPTEuNSkgICsKICBnZW9tX3RleHQoY29sb3I9J3doaXRlJykgKwogIGFubm90YXRlKAogICAgZ2VvbSA9ICJ0ZXh0IiwgeCA9ICdhZGFwdGFiaWxpdHlfbGV2ZWwnLCB5ID0gLTEuNSwgCiAgICBsYWJlbCA9ICdSYXRlZCBMb3dlcicsIGhqdXN0ID0gMCwgdmp1c3QgPSAyLCBzaXplID0gOCkgKwogIGFubm90YXRlKAogICAgZ2VvbSA9ICJ0ZXh0IiwgeCA9ICdhZGFwdGFiaWxpdHlfbGV2ZWwnLCB5ID0gMC43NSwgCiAgICBsYWJlbCA9ICdSYXRlZCBIaWdoZXInLCBoanVzdCA9IDAsIHZqdXN0ID0gMiwgc2l6ZSA9IDgpICsKICBwbG90X3RoZW1lICsKICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpKSArCiAgI3lsaW0oLTEsMykgKwogIGNvb3JkX2ZsaXAoKSArCiAgbGFicyh0aXRsZT0nTWVhbiBvZiBBdHRyaWJ1dGVzIGZvciBFYWNoIENsdXN0ZXIgb2YgRG9nIEJyZWVkcycgLAogICAgICAgc3VidGl0bGUgPSAnJyAsCiAgICAgIHg9JycseT0nJyAsIAogICAgICBjYXB0aW9uPSdQbG90OiBAaXRzbmF0cml2ZXJhICAgIERhdGE6IEFtZXJpY2FuIEtlbm5lbCBDbHViJykgKwogIHNjYWxlX2NvbG9yX21hbnVhbChicmVha3MgPSBjKCcxJywnMicsJzMnLCc0JywnNScsJzYnLCc3JywnOCcpLAogICAgICAgICAgICAgICAgICAgICB2YWx1ZXM9YygiIzAwOUU3MyIsICIjRTY5RjAwIiwgIiM1NkI0RTkiLCAiIzAwMDAwMCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICIjMjkzMzUyIiwgIiMwMDcyQjIiLCAiI0Q1NUUwMCIsICIjQ0M3OUE3IikpIAoKcGxvdF9jbHVzdAoKYGBgCgogCgogCgogCgogCgogCgpgYGB7ciB9CnBsb3RfbmFtZXMgPC0gZG9nX2JyZWVkICU+JQogIGdyb3VwX2J5KGNsdXN0ZXIpICU+JQogIG11dGF0ZShjb3VudCA9IHNlcXVlbmNlKG4oKSkgICwKICAgICAgICAgY291bnR4ID0gaWZlbHNlKGNvdW50JSUyPT0wLC0wLjUsMC41KSApICU+JQogIGdncGxvdChhZXMoeD1jb3VudHgseT1jb3VudCAsIGxhYmVsPWJyZWVkICxjb2xvcj1hcy5mYWN0b3IoY2x1c3RlcikgICkpICsKIGdlb21fdGV4dChzaXplPTQuOCkgKwogIGZhY2V0X3dyYXAofmNsdXN0ZXIgLCBuY29sID0gMiAsICBzY2FsZXM9ImZyZWVfeSIpICsKICB4bGltKGMoLTEsMSkpICsKICBwbG90X3RoZW1lICsKICB0aGVtZShheGlzLnRpdGxlLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRpY2tzLng9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGl0bGUueT1lbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50ZXh0Lnk9ZWxlbWVudF9ibGFuaygpLAogICAgICAgIGF4aXMudGlja3MueT1lbGVtZW50X2JsYW5rKCkgLAogICAgICAgIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dCgKICAgICAgICAgICAgICBzaXplID0gMTIsIGNvbG9yID0gIndoaXRlIiwgZmFjZSA9ICJib2xkIiksCiAgICAgICAgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdCgKICAgICAgICAgICAgY29sb3I9ImJsYWNrIiwgZmlsbD0iIzAwMDAwMCIsIHNpemU9MS41LCBsaW5ldHlwZT0ic29saWQiKSwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3IgPSAiYmxhY2siLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxsID0gTkEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSAyKSkgKwogIGxhYnModGl0bGU9JzggQ2x1c3RlcnMgb2YgRG9nIEJyZWVkcycgLAogICAgICAgc3VidGl0bGUgPSAnJyApICsKICBzY2FsZV9jb2xvcl9tYW51YWwoYnJlYWtzID0gYygnMScsJzInLCczJywnNCcsJzUnLCc2JywnNycsJzgnKSwKICAgICAgICAgICAgICAgICAgICAgdmFsdWVzPWMoIiMwMDlFNzMiLCAiI0U2OUYwMCIsICIjNTZCNEU5IiwgIiMwMDAwMDAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiIzI5MzM1MiIsICIjMDA3MkIyIiwgIiNENTVFMDAiLCAiI0NDNzlBNyIpKQogICAgICAKCnBsb3RfbmFtZXMKYGBgCgogCgogCgogCgogCgpgYGB7ciAgZmlnLndpZHRoPTgsZmlnLmhlaWdodD01fQpnZ2FycmFuZ2UocGxvdF9uYW1lcyAsIHBsb3RfY2x1c3QpCmBgYAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKIAoKCgoKCgoKCgoK